using Serilog;
using Serilog.Events;
using Serilog.Context;
using System.Diagnostics;

var builder = WebApplication.CreateBuilder(args);

// 配置 Serilog
Log.Logger = new LoggerConfiguration().MinimumLevel
    .Information()
    // 过滤掉不必要的 ASP.NET Core 内部日志
    .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
    .MinimumLevel.Override("System", LogEventLevel.Warning)
    .MinimumLevel.Override("Microsoft.AspNetCore.Hosting.Diagnostics", LogEventLevel.Warning)
    .MinimumLevel.Override("Microsoft.AspNetCore.Routing", LogEventLevel.Warning)
    .MinimumLevel.Override("Microsoft.AspNetCore.Mvc", LogEventLevel.Warning)
    // 保留程序生命周期日志
    .MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Information)
    // 控制台日志
    .WriteTo.Console(
        outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}"
    )
    // 主日志文件 - 包含所有信息级别以上的日志（排除异常）
    .WriteTo.File(
        path: "../logs/app-.log",
        rollingInterval: RollingInterval.Day,
        retainedFileCountLimit: 30,
        fileSizeLimitBytes: 10 * 1024 * 1024,
        outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] {Message:lj}{NewLine}{Exception}",
        restrictedToMinimumLevel: LogEventLevel.Information
    )
    // 异常日志文件 - 只记录错误和致命级别的日志，且独立存储
    .WriteTo.Logger(
        lc =>
            lc.Filter
                .ByIncludingOnly(evt => evt.Level >= LogEventLevel.Error)
                .WriteTo.File(
                    path: "../logs/errors-.log",
                    rollingInterval: RollingInterval.Day,
                    retainedFileCountLimit: 30,
                    outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] {SourceContext}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}"
                )
    )
    .Enrich.FromLogContext()
    .CreateLogger();

// 使用 Serilog
builder.Host.UseSerilog();

// 添加服务
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddOpenApi();

var app = builder.Build();

// 记录应用程序启动信息
var logger = app.Services.GetRequiredService<ILogger<Program>>();
var environment = app.Services.GetRequiredService<IHostEnvironment>();
var configuration = app.Services.GetRequiredService<IConfiguration>();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

// 使用自定义的请求日志中间件，避免重复记录异常
app.UseCustomRequestLogging();

app.UseAuthorization();

app.MapControllers();

// 示例端点 - 正常情况
app.MapGet(
    "/",
    (ILogger<Program> logger) =>
    {
        logger.LogInformation("手动日志: 访问了根路径");
        return new { message = "Hello World!", timestamp = DateTime.Now };
    }
);

app.MapGet(
    "/api/users",
    (ILogger<Program> logger) =>
    {
        logger.LogInformation("手动日志: 开始获取用户列表");

        // 模拟处理
        Thread.Sleep(100);

        var users = new[] { new { id = 1, name = "张三" }, new { id = 2, name = "李四" } };

        logger.LogInformation("手动日志: 成功获取 {UserCount} 个用户", users.Length);

        return Results.Ok(users);
    }
);

// 示例端点 - 抛出异常的情况
app.MapGet(
    "/api/error-test",
    (ILogger<Program> logger) =>
    {
        logger.LogWarning("手动日志: 开始执行会抛出异常的操作");

        // 手动记录一些业务日志
        logger.LogInformation("手动日志: 执行某些业务逻辑...");

        // 模拟业务异常
        throw new InvalidOperationException("这是一个测试异常，用于验证异常日志记录");
    }
);

app.MapGet(
    "/api/products/{id:int}",
    (int id, ILogger<Program> logger) =>
    {
        using (LogContext.PushProperty("ProductId", id))
        {
            logger.LogInformation("手动日志: 开始查询产品信息，产品ID: {ProductId}", id);

            if (id > 100)
            {
                // 这是业务逻辑的警告，不是异常
                logger.LogWarning("手动日志: 产品ID {ProductId} 不存在", id);
                return Results.NotFound(new { error = "产品不存在" });
            }

            if (id == 50)
            {
                // 模拟一个业务异常
                throw new ArgumentException("产品ID 50 存在数据问题");
            }

            var product = new
            {
                id = id,
                name = $"产品 {id}",
                price = 99.99m
            };
            logger.LogInformation("手动日志: 成功查询到产品 {ProductName}", product.name);

            return Results.Ok(product);
        }
    }
);

app.MapPost(
    "/api/orders",
    (OrderRequest request, ILogger<Program> logger) =>
    {
        logger.LogInformation(
            "手动日志: 开始创建订单，产品: {ProductName}, 数量: {Quantity}",
            request.ProductName,
            request.Quantity
        );

        if (string.IsNullOrEmpty(request.ProductName))
        {
            logger.LogError("手动日志: 产品名称为空");
            return Results.BadRequest(new { error = "产品名称不能为空" });
        }

        // 模拟订单处理
        Thread.Sleep(200);

        var orderId = Guid.NewGuid();
        logger.LogInformation("手动日志: 订单创建成功，订单号: {OrderId}", orderId);

        return Results.Ok(new { orderId, status = "created" });
    }
);

app.Run();

// 自定义请求日志中间件，避免重复记录异常
public static class RequestLoggingExtensions
{
    public static IApplicationBuilder UseCustomRequestLogging(this IApplicationBuilder app)
    {
        return app.UseMiddleware<CustomRequestLoggingMiddleware>();
    }
}

public class CustomRequestLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<CustomRequestLoggingMiddleware> _logger;

    public CustomRequestLoggingMiddleware(
        RequestDelegate next,
        ILogger<CustomRequestLoggingMiddleware> logger
    )
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var sw = Stopwatch.StartNew();
        var startTime = DateTime.UtcNow;

        try
        {
            await _next(context);
            sw.Stop();

            // 只有成功请求才记录完成信息
            // 通过检查是否已经有异常处理标记来避免重复记录
            if (!context.Items.ContainsKey("ExceptionHandled"))
            {
                using (LogContext.PushProperty("RequestPath", context.Request.Path))
                using (LogContext.PushProperty("RequestMethod", context.Request.Method))
                using (LogContext.PushProperty("StatusCode", context.Response.StatusCode))
                using (LogContext.PushProperty("ElapsedMs", sw.ElapsedMilliseconds))
                {
                    var level =
                        context.Response.StatusCode > 499
                            ? LogEventLevel.Error
                            : context.Response.StatusCode > 399
                                ? LogEventLevel.Warning
                                : LogEventLevel.Information;

                    _logger.LogInformation(
                        "{RequestMethod} {RequestPath} {StatusCode} in {ElapsedMs}ms",
                        context.Request.Method,
                        context.Request.Path,
                        context.Response.StatusCode,
                        sw.ElapsedMilliseconds
                    );
                }
            }
        }
        catch (Exception)
        {
            sw.Stop();

            // 标记异常已被处理，避免重复记录
            context.Items["ExceptionHandled"] = true;

            // 异常已经在全局异常处理中间件中记录了，这里不再重复记录
            // 只记录请求失败的信息（不含异常详情）
            using (LogContext.PushProperty("RequestPath", context.Request.Path))
            using (LogContext.PushProperty("RequestMethod", context.Request.Method))
            {
                _logger.LogWarning(
                    "{RequestMethod} {RequestPath} in {ElapsedMs}ms",
                    context.Request.Method,
                    context.Request.Path,
                    sw.ElapsedMilliseconds
                );
            }

            throw;
        }
    }
}

// 请求模型
public record OrderRequest(string ProductName, int Quantity);
